/*
 * Change Logs:
 * Date           Author       Notes
 * 2022-03-27     chenbin
 */
#include "fload.h"
#if (FBOOT_USING_FLOAD == 1)

#define DBG_ENABLE
#define DBG_SECTION_NAME "fload"
#define DBG_LEVEL DBG_INFO
#include <rtdbg.h>

int fload_fal(const char *part_name, uint32_t load_addr, uint32_t load_max, uint32_t fal_offset)
{
	int ret = 0;
	size_t read_rc = 0;
	
	uint32_t tick_start,tick_end;
	
	const struct fal_partition *part = NULL;

	LOG_I("%s(\"%s\", 0x%08X, 0x%08X, 0x%08X);", __FUNCTION__, part_name, load_addr, load_max, fal_offset);
	part = fal_partition_find(part_name);
	if (part == NULL)
	{
		LOG_I("fal: %s not find!!!", part_name);
		goto __exit;
	}
	if(fal_offset > part->len)
	{
		LOG_I("offset:%d > fal->len:%d", fal_offset, part->len);
		goto __exit;
	}
	if (load_max == 0)
	{
		load_max = part->len;
	}
	if (load_max > (part->len - fal_offset))
	{
		load_max = (part->len - fal_offset);
	}
	
	LOG_I("load start.");
	tick_start = rt_tick_get();
	
	read_rc = fal_partition_read(part, fal_offset, (uint8_t *)(load_addr), load_max);
	
	tick_end = rt_tick_get();
	LOG_I("load %08d / %08d bytes.", read_rc, load_max);
	
	read_rc = ((load_max * 1000U) /(tick_end - tick_start));
	LOG_I("load used: %d ms , average speed: %d bytes/s ",(tick_end - tick_start), read_rc );
	LOG_I("load end.");
	ret = 1;

__exit:
	return ret;
}




#if (FBOOT_USING_FILESYSTEM == 1)

#ifdef RT_USING_DFS
#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#endif

#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/time.h>
#include <sys/ioctl.h>

static int file_is_exist(const char *filepath)
{
	struct stat filestat = {0};
	if (filepath != NULL)
	{
		if ((stat(filepath, &filestat) >= 0) && (!S_ISDIR(filestat.st_mode)))
		{
			return 1;
		}
	}
	return 0;
}

int fload_fs(const char *file_path,  uint32_t load_addr, uint32_t load_max, uint32_t file_offset)
{
	int ret = 0;
	int file_len = 0;
	size_t read_rc = 0;
	
	uint32_t tick_start,tick_end;
	
	int fd = 0;
	
	LOG_I("%s(\"%s\", 0x%08X, 0x%08X, 0x%08X);", __FUNCTION__, file_path, load_addr, load_max, file_offset);
	
	fd = file_is_exist(file_path);
	if (fd == 0)
	{
		LOG_E("file can`t find (%s)", file_path);
		goto __exit;
	}
	fd = open(file_path, O_RDONLY, 0);
	if (fd < 0)
	{
		LOG_E("file can`t open (%s)", file_path);
		goto __exit;
	}
	file_len = lseek(fd, 0L, SEEK_END);
	lseek(fd, 0, SEEK_SET);
	
	if (file_offset > file_len)
	{
		LOG_I("offset:%d > file_len:%d", file_offset, file_len);
		goto __exit;
	}
	if (load_max == 0)
	{
		load_max = file_len;
	}
	if (load_max > (file_len - file_offset))
	{
		load_max = (file_len - file_offset);
	}

	lseek(fd, file_offset, SEEK_SET);
	LOG_I("load start.");
	tick_start = rt_tick_get();
	
	read_rc = read(fd, (void*)(load_addr), load_max);
	
	tick_end = rt_tick_get();
	LOG_I("load %08d / %08d bytes.", read_rc, load_max);
	
	read_rc = ((load_max * 1000U) /(tick_end - tick_start));
	LOG_I("load used: %d ms , average speed: %d bytes/s ",(tick_end - tick_start), read_rc );
	LOG_I("load end.");
	ret = 1;

__exit:
	if (fd >= 0)
	{
		close(fd);
	}
	return ret;
}

#endif


#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
#include <finsh.h>

static const char *help_info[] =
{
	"fload fal <fal part name> <load addr> <load max> [fal offset] (hex/dec)\n\r",
#if (FBOOT_USING_FILESYSTEM == 1)
	"fload fs  <file path>     <load addr> <load max> [file offset] (hex/dec)\n\r",
#endif
};

void fload_cmd(rt_uint8_t argc, char **argv)
{
	int temp1 = 0;
	int temp2 = 0;
	int temp3 = 0;
	if (argc > 4)
	{
		const char *cmd = argv[1];
		if (!rt_strcmp(cmd, "fal"))
		{
			temp1 = fboot_str2int(argv[3]);
			temp2 = fboot_str2int(argv[4]);
			temp3 = fboot_str2int(argv[5]);
			fload_fal(argv[2],temp1,temp2,temp3);
			return;
		}
#if (FBOOT_USING_FILESYSTEM == 1)
		if (!rt_strcmp(cmd, "fs"))
		{
			temp1 = fboot_str2int(argv[3]);
			temp2 = fboot_str2int(argv[4]);
			temp3 = fboot_str2int(argv[5]);
			fload_fs(argv[2],temp1,temp2,temp3);
			return;
		}
#endif
	}
	{
		rt_kprintf("usage:\n");
		for (int i = 0; i < sizeof(help_info) / sizeof(char *); i++)
		{
			rt_kputs(help_info[i]);
		}
		rt_kprintf("\n");
	}
}
MSH_CMD_EXPORT_ALIAS(fload_cmd, fload, fload [fal/fs]);

#endif

#endif
